package com.wmzdq.config;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.authentication.encoding.Md5PasswordEncoder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;

import com.wmzdq.common.IMenuService;
import com.wmzdq.common.IRoleMenuService;
import com.wmzdq.common.IRoleService;
import com.wmzdq.common.IUserService;
import com.wmzdq.security.AccessDecisionManager;
import com.wmzdq.security.ForceHttpsRedirectStrategy;
import com.wmzdq.security.LoginAuthenticationSuccesssHandler;
import com.wmzdq.security.SecurityFilter;
import com.wmzdq.security.SecurityMetadataSource;
import com.wmzdq.security.UserDetailService;
import com.wmzdq.security.UsernamePasswordAuthenticationFilter;

//spring-security的配置
@EnableGlobalMethodSecurity(prePostEnabled=true)
@Configuration
@EnableWebSecurity

public class WebSecurityConfiguartion  extends WebSecurityConfigurerAdapter   {

    
    @Autowired
    UserDetailsService userDetail;
    
    @Autowired
    DaoAuthenticationProvider provider;
    
   // @Autowired
   // ProviderManager manager;
    
    @Autowired
    private IMenuService menuService;
    
    @Autowired
    AccessDecisionManager decisionManager;
    
    @Autowired
    private IRoleService roleService;
    
    @Autowired
    private IRoleMenuService roleMenuService;
    
    @Autowired
    private IUserService userService;
    

    @Autowired
    ForceHttpsRedirectStrategy httpsStrategy;
    
    @Autowired
    Environment env;
    
    
    //不需要权限控制的链接
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/images/**").antMatchers("/js/**").antMatchers("/login").
        							antMatchers("/test/**")
        							.antMatchers("/template/**");
    }
    
    @Bean
    public SecurityMetadataSource metadataSource(){
        SecurityMetadataSource metadataSource=new SecurityMetadataSource(menuService);
        return metadataSource;
    }
    
    @Bean
    public LoginUrlAuthenticationEntryPoint entryPoint(){
        LoginUrlAuthenticationEntryPoint point=new LoginUrlAuthenticationEntryPoint("/login");
        boolean https=Boolean.parseBoolean(env.getProperty("forceHttps"));
        point.setForceHttps(https);
        return point;
    }
    
    //复写 userdetailsservice 
    @Bean
    @Override
    public UserDetailsService userDetailsServiceBean() throws Exception {
       UserDetailService service=new UserDetailService(userService,roleMenuService,roleService,menuService);
       return service;
    }
    
    @Override
    public UserDetailsService userDetailsService() {
       UserDetailService service=new UserDetailService(userService,roleMenuService,roleService,menuService);
       return service;
    }
    
    //复写 manager,如果要启用注解支持，及@postAuthorize等，需要把AuthenticationManager暴露成bean，
    //需要复写这个方法，不然默认不会暴露成bean,同时还要使用注解 @EnableGlobalMethodSecurity
    @Bean(name="myAuthenticationManager")
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        List<AuthenticationProvider> providers =new ArrayList<AuthenticationProvider>();
        providers.add(provider);
        ProviderManager manager=new ProviderManager(providers);
        manager.setEraseCredentialsAfterAuthentication(false);
        return manager;
    }
    
   /* @Override
    public AuthenticationManager authenticationManager(){
        List<AuthenticationProvider> providers =new ArrayList<AuthenticationProvider>();
        providers.add(provider);
        ProviderManager manager=new ProviderManager(providers);
        manager.setEraseCredentialsAfterAuthentication(false);
        return manager;
    }*/
    
    @Bean
    public DaoAuthenticationProvider  provider(UserDetailService service){
        DaoAuthenticationProvider provider=new DaoAuthenticationProvider();
        provider.setHideUserNotFoundExceptions(false);
        provider.setUserDetailsService(service);
        provider.setPasswordEncoder(new Md5PasswordEncoder());
        return provider;
    }
    
    /*@Bean(name="authenticationManager")
    public ProviderManager providerManager(DaoAuthenticationProvider dao){
        
    }*/
    
  //重定向到https策略
    @Bean(name="forceHttpRedirectStrategy")
    public ForceHttpsRedirectStrategy httpsStrategy(){
        ForceHttpsRedirectStrategy strategy=new ForceHttpsRedirectStrategy();
        return strategy;
    }
    
    //登录成功处理器
    @Bean(name="loginLogAuthenticationSuccessHandler")
    public LoginAuthenticationSuccesssHandler successHandler(){
        LoginAuthenticationSuccesssHandler handler=new LoginAuthenticationSuccesssHandler();
        //成功后的默认跳转界面
        handler.setDefaultTargetUrl("/index");
        //跳转策略
        handler.setRedirectStrategy(httpsStrategy());
        //是否总是返回 defaultTargetUrl的页面，如果是false，那么会根据 head或者request里的参数跳转，详情看代码 
        handler.setAlwaysUseDefaultTargetUrl(true);
        return handler;
    }
    
    //登录失败处理器
    @Bean(name="simpleUrlAuthenticationFailureHandler")
    public SimpleUrlAuthenticationFailureHandler failureHandler(){
        SimpleUrlAuthenticationFailureHandler handler=new SimpleUrlAuthenticationFailureHandler();
        handler.setDefaultFailureUrl("/login");
       // handler.setUseForward(true);
        handler.setRedirectStrategy(httpsStrategy());
        return handler;
    }
    
    //登录拦截器,验证用户名，密码
    public UsernamePasswordAuthenticationFilter usernameFilter() throws Exception {   
        UsernamePasswordAuthenticationFilter filter=new UsernamePasswordAuthenticationFilter(roleMenuService,roleService,menuService);
        filter.setFilterProcessesUrl("/doSecurity");
        filter.setAuthenticationManager(authenticationManagerBean());
        filter.setAuthenticationSuccessHandler(successHandler());
        filter.setAuthenticationFailureHandler(failureHandler());
        return filter;
       
    }
    
    //权限验证器
    @Bean(name="accessDecisionManager")
    public AccessDecisionManager decisManager(){
        AccessDecisionManager manager=new AccessDecisionManager();
        return manager;
    }
    

    
    //登陆后，访问验证
    @Bean(name="securityFilter")
    public SecurityFilter securityFilter() throws Exception {
        SecurityFilter filter=new SecurityFilter();
        filter.setAuthenticationManager(authenticationManagerBean());
        filter.setAccessDecisionManager(decisionManager);
        filter.setSecurityMetadataSource(metadataSource());
        
        return filter;
        
    }
    
    //注销拦截器
    @Bean(name="logoutFilter")
    public LogoutFilter logoutFilter(){
        SimpleUrlLogoutSuccessHandler handler=new SimpleUrlLogoutSuccessHandler();
        handler.setRedirectStrategy(httpsStrategy);
        handler.setDefaultTargetUrl("/login");
        handler.setAlwaysUseDefaultTargetUrl(true);
        LogoutHandler[] logouts=new LogoutHandler[1];
        logouts[0]=new SecurityContextLogoutHandler();
        
        LogoutFilter filter=new LogoutFilter(handler,logouts );
        filter.setFilterProcessesUrl("/loginOut");
        return filter;
    }
    
    
    
    
    @Override
    public void configure(HttpSecurity http) throws Exception {
        
        http.
            csrf().disable()
            .sessionManagement().
                invalidSessionUrl("/login").
        and()
            .addFilterAt(usernameFilter(), UsernamePasswordAuthenticationFilter.class)
            .addFilterBefore(securityFilter(), FilterSecurityInterceptor.class)
            .addFilterAt(logoutFilter(), LogoutFilter.class)
            .exceptionHandling()
                .authenticationEntryPoint(entryPoint())
                //maxSessionsPreventsLogin 方法 ，等同于XML配置error-if-maximum-exceeded
                .and().sessionManagement().maximumSessions(1).maxSessionsPreventsLogin(true);
    }
    
}
